package yunjiao.javatutorials.guava.concurrent;

import com.google.common.util.concurrent.Monitor;

/**
 * 读写锁实现
 *
 * @author yangyunjiao
 */
public class ReadWriteLockWithMonitor {
    private final Monitor monitor = new Monitor();
    private int readers = 0;
    private boolean writer = false;

    // 读锁条件：没有写线程
    private final Monitor.Guard canRead = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return !writer;
        }
    };

    // 写锁条件：没有读线程和写线程
    private final Monitor.Guard canWrite = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return readers == 0 && !writer;
        }
    };

    public void acquireReadLock() throws InterruptedException {
        monitor.enterWhen(canRead);
        try {
            readers++;
        } finally {
            monitor.leave();
        }
    }

    public void releaseReadLock() {
        monitor.enter();
        try {
            readers--;
            if (readers < 0) readers = 0;
        } finally {
            monitor.leave();
        }
    }

    public void acquireWriteLock() throws InterruptedException {
        monitor.enterWhen(canWrite);
        try {
            writer = true;
        } finally {
            monitor.leave();
        }
    }

    public void releaseWriteLock() {
        monitor.enter();
        try {
            writer = false;
        } finally {
            monitor.leave();
        }
    }

    // 使用示例
    public String readData() throws InterruptedException {
        acquireReadLock();
        try {
            // 模拟读取操作
            Thread.sleep(10);
            return "data";
        } finally {
            releaseReadLock();
        }
    }

    public void writeData(String data) throws InterruptedException {
        acquireWriteLock();
        try {
            // 模拟写入操作
            Thread.sleep(20);
        } finally {
            releaseWriteLock();
        }
    }
}
